﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Settlements.Settlement
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using TaleWorlds.CampaignSystem.Encounters;
using TaleWorlds.CampaignSystem.GameState;
using TaleWorlds.CampaignSystem.Map;
using TaleWorlds.CampaignSystem.MapEvents;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Party.PartyComponents;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.CampaignSystem.Settlements.Buildings;
using TaleWorlds.CampaignSystem.Settlements.Locations;
using TaleWorlds.CampaignSystem.Siege;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.ObjectSystem;
using TaleWorlds.SaveSystem;
using TaleWorlds.SaveSystem.Load;

#nullable disable
namespace TaleWorlds.CampaignSystem.Settlements
{
  public sealed class Settlement : 
    MBObjectBase,
    ILocatable<Settlement>,
    IMapPoint,
    ITrackableCampaignObject,
    ITrackableBase,
    ISiegeEventSide,
    IMapEntity,
    IRandomOwner
  {
    [SaveableField(102)]
    public int NumberOfLordPartiesTargeting;
    [CachedData]
    private int _numberOfLordPartiesAt;
    [SaveableField(104)]
    public int CanBeClaimed;
    [SaveableField(105)]
    public float ClaimValue;
    [SaveableField(106)]
    public Hero ClaimedBy;
    [SaveableField(107)]
    public bool HasVisited;
    [SaveableField(110)]
    public float LastVisitTimeOfOwner;
    [SaveableField(113)]
    private bool _isVisible;
    [CachedData]
    private int _locatorNodeIndex;
    [SaveableField(117)]
    private Settlement _nextLocatable;
    [CachedData]
    private float _oldProsperityObsolete = -1f;
    [SaveableField(119)]
    private float _readyMilitia;
    [SaveableField(120)]
    private MBList<float> _settlementWallSectionHitPointsRatioList = new MBList<float>();
    [CachedData]
    private MBList<MobileParty> _partiesCache;
    [CachedData]
    private MBList<Hero> _heroesWithoutPartyCache;
    [CachedData]
    private MBList<Hero> _notablesCache;
    private Vec2 _gatePosition;
    private Vec2 _position;
    public CultureObject Culture;
    private TextObject _name;
    [SaveableField(129)]
    private MBList<Village> _boundVillages;
    [SaveableField(131)]
    private MobileParty _lastAttackerParty;
    [SaveableField(148)]
    private MBList<SiegeEvent.SiegeEngineMissile> _siegeEngineMissiles;
    public Town Town;
    public Village Village;
    public Hideout Hideout;
    [CachedData]
    public MilitiaPartyComponent MilitiaPartyComponent;
    [SaveableField(145)]
    public readonly ItemRoster Stash;

    internal static void AutoGeneratedStaticCollectObjectsSettlement(
      object o,
      List<object> collectedObjects)
    {
      ((MBObjectBase) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected override void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      base.AutoGeneratedInstanceCollectObjects(collectedObjects);
      collectedObjects.Add((object) this.ClaimedBy);
      collectedObjects.Add((object) this.Stash);
      collectedObjects.Add((object) this._nextLocatable);
      collectedObjects.Add((object) this._settlementWallSectionHitPointsRatioList);
      collectedObjects.Add((object) this._boundVillages);
      collectedObjects.Add((object) this._lastAttackerParty);
      collectedObjects.Add((object) this._siegeEngineMissiles);
      collectedObjects.Add((object) this.Party);
      collectedObjects.Add((object) this.SiegeEvent);
      collectedObjects.Add((object) this.SettlementComponent);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.LastThreatTime, collectedObjects);
      collectedObjects.Add((object) this.SiegeEngines);
      collectedObjects.Add((object) this.SiegeStrategy);
      collectedObjects.Add((object) this.Alleys);
      collectedObjects.Add((object) this.LocationComplex);
    }

    internal static object AutoGeneratedGetMemberValueParty(object o)
    {
      return (object) ((Settlement) o).Party;
    }

    internal static object AutoGeneratedGetMemberValueBribePaid(object o)
    {
      return (object) ((Settlement) o).BribePaid;
    }

    internal static object AutoGeneratedGetMemberValueSiegeEvent(object o)
    {
      return (object) ((Settlement) o).SiegeEvent;
    }

    internal static object AutoGeneratedGetMemberValueIsActive(object o)
    {
      return (object) ((Settlement) o).IsActive;
    }

    internal static object AutoGeneratedGetMemberValueNumberOfEnemiesSpottedAround(object o)
    {
      return (object) ((Settlement) o).NumberOfEnemiesSpottedAround;
    }

    internal static object AutoGeneratedGetMemberValueNumberOfAlliesSpottedAround(object o)
    {
      return (object) ((Settlement) o).NumberOfAlliesSpottedAround;
    }

    internal static object AutoGeneratedGetMemberValueSettlementHitPoints(object o)
    {
      return (object) ((Settlement) o).SettlementHitPoints;
    }

    internal static object AutoGeneratedGetMemberValueSettlementComponent(object o)
    {
      return (object) ((Settlement) o).SettlementComponent;
    }

    internal static object AutoGeneratedGetMemberValueGarrisonWagePaymentLimit(object o)
    {
      return (object) ((Settlement) o).GarrisonWagePaymentLimit;
    }

    internal static object AutoGeneratedGetMemberValueLastThreatTime(object o)
    {
      return (object) ((Settlement) o).LastThreatTime;
    }

    internal static object AutoGeneratedGetMemberValueSiegeEngines(object o)
    {
      return (object) ((Settlement) o).SiegeEngines;
    }

    internal static object AutoGeneratedGetMemberValueNumberOfTroopsKilledOnSide(object o)
    {
      return (object) ((Settlement) o).NumberOfTroopsKilledOnSide;
    }

    internal static object AutoGeneratedGetMemberValueSiegeStrategy(object o)
    {
      return (object) ((Settlement) o).SiegeStrategy;
    }

    internal static object AutoGeneratedGetMemberValueAlleys(object o)
    {
      return (object) ((Settlement) o).Alleys;
    }

    internal static object AutoGeneratedGetMemberValueLocationComplex(object o)
    {
      return (object) ((Settlement) o).LocationComplex;
    }

    internal static object AutoGeneratedGetMemberValueCurrentSiegeState(object o)
    {
      return (object) ((Settlement) o).CurrentSiegeState;
    }

    internal static object AutoGeneratedGetMemberValueNumberOfLordPartiesTargeting(object o)
    {
      return (object) ((Settlement) o).NumberOfLordPartiesTargeting;
    }

    internal static object AutoGeneratedGetMemberValueCanBeClaimed(object o)
    {
      return (object) ((Settlement) o).CanBeClaimed;
    }

    internal static object AutoGeneratedGetMemberValueClaimValue(object o)
    {
      return (object) ((Settlement) o).ClaimValue;
    }

    internal static object AutoGeneratedGetMemberValueClaimedBy(object o)
    {
      return (object) ((Settlement) o).ClaimedBy;
    }

    internal static object AutoGeneratedGetMemberValueHasVisited(object o)
    {
      return (object) ((Settlement) o).HasVisited;
    }

    internal static object AutoGeneratedGetMemberValueLastVisitTimeOfOwner(object o)
    {
      return (object) ((Settlement) o).LastVisitTimeOfOwner;
    }

    internal static object AutoGeneratedGetMemberValueStash(object o)
    {
      return (object) ((Settlement) o).Stash;
    }

    internal static object AutoGeneratedGetMemberValue_isVisible(object o)
    {
      return (object) ((Settlement) o)._isVisible;
    }

    internal static object AutoGeneratedGetMemberValue_nextLocatable(object o)
    {
      return (object) ((Settlement) o)._nextLocatable;
    }

    internal static object AutoGeneratedGetMemberValue_readyMilitia(object o)
    {
      return (object) ((Settlement) o)._readyMilitia;
    }

    internal static object AutoGeneratedGetMemberValue_settlementWallSectionHitPointsRatioList(
      object o)
    {
      return (object) ((Settlement) o)._settlementWallSectionHitPointsRatioList;
    }

    internal static object AutoGeneratedGetMemberValue_boundVillages(object o)
    {
      return (object) ((Settlement) o)._boundVillages;
    }

    internal static object AutoGeneratedGetMemberValue_lastAttackerParty(object o)
    {
      return (object) ((Settlement) o)._lastAttackerParty;
    }

    internal static object AutoGeneratedGetMemberValue_siegeEngineMissiles(object o)
    {
      return (object) ((Settlement) o)._siegeEngineMissiles;
    }

    [SaveableProperty(101)]
    public PartyBase Party { get; private set; }

    public int NumberOfLordPartiesAt => this._numberOfLordPartiesAt;

    [SaveableProperty(116)]
    public int BribePaid { get; set; }

    [SaveableProperty(111)]
    public SiegeEvent SiegeEvent { get; set; }

    [SaveableProperty(112)]
    public bool IsActive { get; set; }

    public Hero Owner => this.OwnerClan.Leader;

    public bool IsVisible
    {
      get => this._isVisible;
      set
      {
        if (this._isVisible == value)
          return;
        this._isVisible = value;
        this.Party.OnVisibilityChanged(value);
      }
    }

    [CachedData]
    public bool IsInspected { get; set; }

    public int WallSectionCount => !this.IsFortification ? 0 : 2;

    int ILocatable<Settlement>.LocatorNodeIndex
    {
      get => this._locatorNodeIndex;
      set => this._locatorNodeIndex = value;
    }

    [SaveableProperty(115)]
    public float NumberOfEnemiesSpottedAround { get; set; }

    [SaveableProperty(128)]
    public float NumberOfAlliesSpottedAround { get; set; }

    Settlement ILocatable<Settlement>.NextLocatable
    {
      get => this._nextLocatable;
      set => this._nextLocatable = value;
    }

    public int RandomValue => this.Party.RandomValue;

    public Vec2 GetPosition2D => this.Position2D;

    public float Militia
    {
      get
      {
        return (this.MilitiaPartyComponent == null || !this.MilitiaPartyComponent.MobileParty.IsActive ? 0.0f : (float) this.MilitiaPartyComponent.MobileParty.Party.NumberOfAllMembers) + this._readyMilitia;
      }
      set
      {
        int numberOfAllMembers = this.MilitiaPartyComponent == null || !this.MilitiaPartyComponent.MobileParty.IsActive ? 0 : this.MilitiaPartyComponent.MobileParty.Party.NumberOfAllMembers;
        this._readyMilitia = value - (float) numberOfAllMembers;
        if ((double) this._readyMilitia < (double) -numberOfAllMembers)
          this._readyMilitia = (float) -numberOfAllMembers;
        if ((double) this._readyMilitia >= -1.0 && (double) this._readyMilitia <= 1.0)
          return;
        if (this.MilitiaPartyComponent != null)
          this.TransferReadyMilitiasToMilitiaParty();
        else
          this.SpawnMilitiaParty();
      }
    }

    public MBReadOnlyList<float> SettlementWallSectionHitPointsRatioList
    {
      get => (MBReadOnlyList<float>) this._settlementWallSectionHitPointsRatioList;
    }

    public float SettlementTotalWallHitPoints
    {
      get
      {
        float num = 0.0f;
        foreach (float sectionHitPointsRatio in (List<float>) this._settlementWallSectionHitPointsRatioList)
          num += sectionHitPointsRatio;
        return num * this.MaxHitPointsOfOneWallSection;
      }
    }

    public float MaxHitPointsOfOneWallSection
    {
      get
      {
        return this.WallSectionCount == 0 ? 0.0f : this.MaxWallHitPoints / (float) this.WallSectionCount;
      }
    }

    public void SetWallSectionHitPointsRatioAtIndex(int index, float hitPointsRatio)
    {
      this._settlementWallSectionHitPointsRatioList[index] = MBMath.ClampFloat(hitPointsRatio, 0.0f, 1f);
    }

    [SaveableProperty(121)]
    public float SettlementHitPoints { get; internal set; }

    public float MaxWallHitPoints
    {
      get
      {
        return Campaign.Current.Models.WallHitPointCalculationModel.CalculateMaximumWallHitPoint(this.Town);
      }
    }

    public MBReadOnlyList<MobileParty> Parties => (MBReadOnlyList<MobileParty>) this._partiesCache;

    public MBReadOnlyList<Hero> HeroesWithoutParty
    {
      get => (MBReadOnlyList<Hero>) this._heroesWithoutPartyCache;
    }

    public MBReadOnlyList<Hero> Notables => (MBReadOnlyList<Hero>) this._notablesCache;

    [SaveableProperty(152)]
    public SettlementComponent SettlementComponent { get; private set; }

    public Vec2 GatePosition
    {
      get => this._gatePosition;
      private set
      {
        this._gatePosition = value;
        Campaign current = Campaign.Current;
        if (current.MapSceneWrapper == null)
          return;
        this.CurrentNavigationFace = current.MapSceneWrapper.GetFaceIndex(this._gatePosition);
      }
    }

    public Vec2 Position2D
    {
      get => this._position;
      private set
      {
        this._position = value;
        Campaign.Current.SettlementLocator.UpdateLocator(this);
      }
    }

    public PathFaceRecord CurrentNavigationFace { get; private set; }

    public Vec3 GetLogicalPosition()
    {
      float height = 0.0f;
      Campaign.Current.MapSceneWrapper.GetHeightAtPoint(this.Position2D, ref height);
      return new Vec3(this.Position2D.x, this.Position2D.y, height);
    }

    public IFaction MapFaction
    {
      get
      {
        return this.Town?.MapFaction ?? this.Village?.Bound.MapFaction ?? this.Hideout?.MapFaction ?? (IFaction) null;
      }
    }

    public TextObject Name
    {
      get => this._name;
      set => this.SetName(value);
    }

    public TextObject EncyclopediaText { get; private set; }

    public string EncyclopediaLink
    {
      get
      {
        return Campaign.Current.EncyclopediaManager.GetIdentifier(typeof (Settlement)) + "-" + this.StringId ?? "";
      }
    }

    public TextObject EncyclopediaLinkWithName
    {
      get => HyperlinkTexts.GetSettlementHyperlinkText(this.EncyclopediaLink, this.Name);
    }

    [SaveableProperty(122)]
    public int GarrisonWagePaymentLimit { get; private set; }

    public void SetGarrisonWagePaymentLimit(int limit) => this.GarrisonWagePaymentLimit = limit;

    public ItemRoster ItemRoster => this.Party.ItemRoster;

    public MBReadOnlyList<Village> BoundVillages => (MBReadOnlyList<Village>) this._boundVillages;

    public MobileParty LastAttackerParty
    {
      get => this._lastAttackerParty;
      set
      {
        if (this._lastAttackerParty == value)
          return;
        this._lastAttackerParty = value;
        if (value != null && (this.IsFortification || this.IsVillage))
        {
          foreach (Settlement settlement in (List<Settlement>) Settlement.All)
          {
            if ((settlement.IsFortification || settlement.IsVillage) && settlement.LastAttackerParty == value)
              settlement.LastAttackerParty = (MobileParty) null;
          }
        }
        this._lastAttackerParty = value;
        if (this._lastAttackerParty == null)
          return;
        this.LastThreatTime = CampaignTime.Now;
      }
    }

    [SaveableProperty(137)]
    public CampaignTime LastThreatTime { get; private set; }

    [SaveableProperty(149)]
    public SiegeEvent.SiegeEnginesContainer SiegeEngines { get; private set; }

    public MBReadOnlyList<SiegeEvent.SiegeEngineMissile> SiegeEngineMissiles
    {
      get => (MBReadOnlyList<SiegeEvent.SiegeEngineMissile>) this._siegeEngineMissiles;
    }

    public BattleSideEnum BattleSide => BattleSideEnum.Defender;

    [SaveableProperty(150)]
    public int NumberOfTroopsKilledOnSide { get; private set; }

    [SaveableProperty(151)]
    public SiegeStrategy SiegeStrategy { get; private set; }

    public IEnumerable<PartyBase> GetInvolvedPartiesForEventType(MapEvent.BattleTypes mapEventType = MapEvent.BattleTypes.Siege)
    {
      return Campaign.Current.Models.EncounterModel.GetDefenderPartiesOfSettlement(this, mapEventType);
    }

    public PartyBase GetNextInvolvedPartyForEventType(
      ref int partyIndex,
      MapEvent.BattleTypes mapEventType = MapEvent.BattleTypes.Siege)
    {
      return Campaign.Current.Models.EncounterModel.GetNextDefenderPartyOfSettlement(this, ref partyIndex, mapEventType);
    }

    public bool HasInvolvedPartyForEventType(PartyBase party, MapEvent.BattleTypes mapEventType = MapEvent.BattleTypes.Siege)
    {
      int partyIndex = -1;
      for (PartyBase partyOfSettlement = Campaign.Current.Models.EncounterModel.GetNextDefenderPartyOfSettlement(this, ref partyIndex, mapEventType); partyOfSettlement != null; partyOfSettlement = Campaign.Current.Models.EncounterModel.GetNextDefenderPartyOfSettlement(this, ref partyIndex, mapEventType))
      {
        if (partyOfSettlement == party)
          return true;
      }
      return false;
    }

    internal void AddBoundVillageInternal(Village village) => this._boundVillages.Add(village);

    internal void RemoveBoundVillageInternal(Village village)
    {
      this._boundVillages.Remove(village);
    }

    [SaveableProperty(133)]
    public List<Alley> Alleys { get; private set; }

    private void SetName(TextObject name)
    {
      this._name = name;
      this.SetNameAttributes();
    }

    private void SetNameAttributes()
    {
      this._name.SetTextVariable("IS_SETTLEMENT", 1);
      this._name.SetTextVariable("IS_CASTLE", this.IsCastle ? 1 : 0);
      this._name.SetTextVariable("IS_TOWN", this.IsTown ? 1 : 0);
      this._name.SetTextVariable("IS_HIDEOUT", this.IsHideout ? 1 : 0);
    }

    private void InitSettlement()
    {
      this._partiesCache = new MBList<MobileParty>();
      this._heroesWithoutPartyCache = new MBList<Hero>();
      this._notablesCache = new MBList<Hero>();
      this._boundVillages = new MBList<Village>();
      this.SettlementHitPoints = 1f;
      this.CurrentSiegeState = Settlement.SiegeState.OnTheWalls;
      this.LastVisitTimeOfOwner = Campaign.CurrentTime;
    }

    public bool IsTown => this.Town != null && this.Town.IsTown;

    public bool IsCastle => this.Town != null && this.Town.IsCastle;

    public bool IsFortification => this.IsTown || this.IsCastle;

    public bool IsVillage => this.Village != null;

    public bool IsHideout => this.Hideout != null;

    public bool IsStarving => this.Town != null && (double) this.Town.FoodStocks <= 0.0;

    public bool IsRaided
    {
      get => this.IsVillage && this.Village.VillageState == Village.VillageStates.Looted;
    }

    public bool InRebelliousState => (this.IsTown || this.IsCastle) && this.Town.InRebelliousState;

    public bool IsUnderRaid => this.Party.MapEvent != null && this.Party.MapEvent.IsRaid;

    public bool IsUnderSiege => this.SiegeEvent != null;

    public bool IsUnderRebellionAttack()
    {
      if (this.Party.MapEvent != null && this.Party.MapEvent.IsSiegeAssault)
      {
        Hero owner = this.Party.MapEvent.AttackerSide.LeaderParty.MobileParty.Party.Owner;
        if (owner != null && owner.Clan.IsRebelClan)
          return true;
      }
      return false;
    }

    public Settlement()
      : this(new TextObject("{=!}unnamed"), (LocationComplex) null, (PartyTemplateObject) null)
    {
    }

    public Settlement(TextObject name, LocationComplex locationComplex, PartyTemplateObject pt)
    {
      this._name = name;
      this._isVisible = true;
      this.IsActive = true;
      this.Party = new PartyBase(this);
      this.InitSettlement();
      this._position = Vec2.Zero;
      this.LocationComplex = locationComplex;
      this.Alleys = new List<Alley>();
      this.HasVisited = false;
      this.Stash = new ItemRoster();
    }

    public float GetSettlementValueForEnemyHero(Hero hero)
    {
      return Campaign.Current.Models.SettlementValueModel.CalculateSettlementValueForEnemyHero(this, hero);
    }

    [SaveableProperty(138)]
    public LocationComplex LocationComplex { get; private set; }

    public static Settlement CurrentSettlement
    {
      get
      {
        if (PlayerCaptivity.CaptorParty != null && PlayerCaptivity.CaptorParty.IsSettlement)
          return PlayerCaptivity.CaptorParty.Settlement;
        if (PlayerEncounter.EncounterSettlement != null)
          return PlayerEncounter.EncounterSettlement;
        return MobileParty.MainParty.CurrentSettlement != null ? MobileParty.MainParty.CurrentSettlement : (Settlement) null;
      }
    }

    public float GetValue(Hero hero = null, bool countAlsoBoundedSettlements = true)
    {
      float num1 = 0.0f;
      if (this.IsVillage)
        num1 = (float) ((100000.0 + (double) this.Village.Hearth * 250.0) * (this.Village.VillageState == Village.VillageStates.Looted ? 0.800000011920929 : (this.Village.VillageState == Village.VillageStates.BeingRaided ? 0.85000002384185791 : 0.800000011920929 + (0.66699999570846558 + 0.33300000429153442 * (double) this.Village.Settlement.SettlementHitPoints) * 0.20000000298023224)));
      else if (this.IsCastle)
        num1 = (float) (250000.0 + (double) this.Town.Prosperity * 1000.0);
      else if (this.IsTown)
        num1 = (float) (750000.0 + (double) this.Town.Prosperity * 1000.0);
      float num2 = 1f;
      if (hero != null && hero.Clan.Settlements.Count > 0)
      {
        float num3 = MathF.Clamp(MathF.Pow((float) ((double) Campaign.Current.Models.MapDistanceModel.GetDistance(hero.Clan.FactionMidSettlement, this) / (double) Campaign.AverageDistanceBetweenTwoFortifications * 4.0), 2f), 0.0f, 100f) - 16f;
        num2 *= (float) ((100.0 - (double) num3) / 100.0);
      }
      if (countAlsoBoundedSettlements)
      {
        foreach (Village boundVillage in (List<Village>) this.BoundVillages)
          num1 += boundVillage.Settlement.GetValue(hero, false);
      }
      return num1 * num2;
    }

    public override TextObject GetName() => this.Name;

    public float GetSettlementValueForFaction(IFaction faction)
    {
      return Campaign.Current.Models.SettlementValueModel.CalculateSettlementValueForFaction(this, faction);
    }

    public override string ToString() => this.Name.ToString();

    internal void AddMobileParty(MobileParty mobileParty)
    {
      if (!this._partiesCache.Contains(mobileParty))
      {
        this._partiesCache.Add(mobileParty);
        if (!mobileParty.IsLordParty)
          return;
        ++this._numberOfLordPartiesAt;
      }
      else
        Debug.FailedAssert("mobileParty is already in mobileParties List!", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Settlements\\Settlement.cs", nameof (AddMobileParty), 648);
    }

    internal void RemoveMobileParty(MobileParty mobileParty)
    {
      if (this._partiesCache.Contains(mobileParty))
      {
        this._partiesCache.Remove(mobileParty);
        if (!mobileParty.IsLordParty)
          return;
        --this._numberOfLordPartiesAt;
      }
      else
        Debug.FailedAssert("mobileParty is not in mobileParties List", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Settlements\\Settlement.cs", nameof (RemoveMobileParty), 667);
    }

    internal void AddHeroWithoutParty(Hero individual)
    {
      if (!this._heroesWithoutPartyCache.Contains(individual))
      {
        this._heroesWithoutPartyCache.Add(individual);
        this.CollectNotablesToCache();
      }
      else
        Debug.FailedAssert("Notable is already in Notable List!", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Settlements\\Settlement.cs", nameof (AddHeroWithoutParty), 686);
    }

    internal void RemoveHeroWithoutParty(Hero individual)
    {
      if (this._heroesWithoutPartyCache.Contains(individual))
      {
        this._heroesWithoutPartyCache.Remove(individual);
        this.CollectNotablesToCache();
      }
      else
        Debug.FailedAssert("Notable is not in Notable List", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Settlements\\Settlement.cs", nameof (RemoveHeroWithoutParty), 700);
    }

    private void CollectNotablesToCache()
    {
      this._notablesCache.Clear();
      foreach (Hero hero in (List<Hero>) this.HeroesWithoutParty)
      {
        if (hero.IsNotable)
          this._notablesCache.Add(hero);
      }
    }

    public override void Deserialize(MBObjectManager objectManager, XmlNode node)
    {
      bool isInitialized = this.IsInitialized;
      base.Deserialize(objectManager, node);
      this.Name = new TextObject(node.Attributes["name"].Value);
      this.Position2D = new Vec2((float) Convert.ToDouble(node.Attributes["posX"].Value), (float) Convert.ToDouble(node.Attributes["posY"].Value));
      this.GatePosition = this.Position2D;
      if (node.Attributes["gate_posX"] != null)
        this.GatePosition = new Vec2((float) Convert.ToDouble(node.Attributes["gate_posX"].Value), (float) Convert.ToDouble(node.Attributes["gate_posY"].Value));
      this.Culture = objectManager.ReadObjectReferenceFromXml<CultureObject>("culture", node);
      this.EncyclopediaText = node.Attributes["text"] != null ? new TextObject(node.Attributes["text"].Value) : TextObject.Empty;
      if (Campaign.Current != null && Campaign.Current.MapSceneWrapper != null && !Campaign.Current.MapSceneWrapper.GetFaceIndex(this.Position2D).IsValid())
        Debug.Print("Center position of settlement(" + (object) this.GetName() + ") is invalid");
      foreach (XmlNode childNode1 in node.ChildNodes)
      {
        if (childNode1.Name == "Components")
        {
          foreach (XmlNode childNode2 in childNode1.ChildNodes)
            this.SetSettlementComponent((SettlementComponent) objectManager.CreateObjectFromXmlNode(childNode2));
        }
        if (childNode1.Name == "Locations")
        {
          LocationComplexTemplate complexTemplate = (LocationComplexTemplate) objectManager.ReadObjectReferenceFromXml("complex_template", typeof (LocationComplexTemplate), childNode1);
          if (!isInitialized)
            this.LocationComplex = new LocationComplex(complexTemplate);
          else
            this.LocationComplex.Initialize(complexTemplate);
          foreach (XmlNode childNode3 in childNode1.ChildNodes)
          {
            if (childNode3.Name == "Location")
            {
              Location locationWithId = this.LocationComplex.GetLocationWithId(childNode3.Attributes["id"].Value);
              if (childNode3.Attributes["max_prosperity"] != null)
                locationWithId.ProsperityMax = int.Parse(childNode3.Attributes["max_prosperity"].Value);
              bool flag = false;
              for (int upgradeLevel = 0; upgradeLevel < 4; ++upgradeLevel)
              {
                string name = "scene_name" + (upgradeLevel > 0 ? "_" + (object) upgradeLevel : "");
                string sceneName = childNode3.Attributes[name] != null ? childNode3.Attributes[name].Value : "";
                flag = flag || !string.IsNullOrEmpty(sceneName);
                locationWithId.SetSceneName(upgradeLevel, sceneName);
              }
            }
          }
        }
        if (childNode1.Name == "CommonAreas")
        {
          int index = 0;
          foreach (XmlNode childNode4 in childNode1.ChildNodes)
          {
            if (childNode4.Name == "Area")
            {
              string str = childNode4.Attributes["name"].Value;
              string tag = "alley_" + (object) (index + 1);
              if (!isInitialized)
                this.Alleys.Add(new Alley(this, tag, new TextObject(str)));
              else
                this.Alleys[index].Initialize(this, tag, new TextObject(str));
              ++index;
            }
          }
          foreach (Alley alley1 in this.Alleys)
          {
            foreach (Alley alley2 in this.Alleys)
              ;
          }
        }
      }
      if (!isInitialized)
      {
        Clan clan = objectManager.ReadObjectReferenceFromXml<Clan>("owner", node);
        if (clan != null && this.Town != null)
          this.Town.OwnerClan = clan;
      }
      this.SetNameAttributes();
    }

    public void OnFinishLoadState()
    {
      if (this.IsFortification)
      {
        foreach (Building building in (List<Building>) this.Town.Buildings)
        {
          if (building.BuildingType.IsDefaultProject && building.CurrentLevel != 1)
            building.CurrentLevel = 1;
        }
      }
      this.Party.UpdateVisibilityAndInspected();
    }

    public void OnGameInitialized()
    {
      this.CurrentNavigationFace = Campaign.Current.MapSceneWrapper.GetFaceIndex(this.GatePosition);
    }

    public void OnGameCreated()
    {
      this.SettlementComponent?.OnInit();
      this.CreateFigure();
      this.Party.SetLevelMaskIsDirty();
      for (int index = 0; index < this.WallSectionCount; ++index)
        this._settlementWallSectionHitPointsRatioList.Add(1f);
    }

    public void OnSessionStart() => this.Party?.SetVisualAsDirty();

    [LoadInitializationCallback]
    private void OnLoad()
    {
      ((ILocatable<Settlement>) this).LocatorNodeIndex = -1;
      this._partiesCache = new MBList<MobileParty>();
      this._heroesWithoutPartyCache = new MBList<Hero>();
      this._notablesCache = new MBList<Hero>();
    }

    [LateLoadInitializationCallback]
    private void OnLateLoad(MetaData metaData, ObjectLoadData objectLoadData)
    {
      if (!MBSaveLoad.IsUpdatingGameVersion || !(MBSaveLoad.LastLoadedGameVersion < ApplicationVersion.FromString("v1.2.0")))
        return;
      this._oldProsperityObsolete = (float) objectLoadData.GetMemberValueBySaveId(118);
    }

    public static Settlement Find(string idString)
    {
      return MBObjectManager.Instance.GetObject<Settlement>(idString);
    }

    public static Settlement FindFirst(Func<Settlement, bool> predicate)
    {
      return Settlement.All.FirstOrDefault<Settlement>(predicate);
    }

    public static IEnumerable<Settlement> FindAll(Func<Settlement, bool> predicate)
    {
      return Settlement.All.Where<Settlement>(predicate);
    }

    public static MBReadOnlyList<Settlement> All => Campaign.Current.Settlements;

    public static Settlement GetFirst => Settlement.All.FirstOrDefault<Settlement>();

    public static LocatableSearchData<Settlement> StartFindingLocatablesAroundPosition(
      Vec2 position,
      float radius)
    {
      return Campaign.Current.SettlementLocator.StartFindingLocatablesAroundPosition(position, radius);
    }

    public static Settlement FindNextLocatable(ref LocatableSearchData<Settlement> data)
    {
      return Campaign.Current.SettlementLocator.FindNextLocatable(ref data);
    }

    public void OnPlayerEncounterFinish() => this.LocationComplex?.ClearTempCharacters();

    TextObject ITrackableBase.GetName() => this.Name;

    public Vec3 GetPosition() => this.GetLogicalPosition();

    public float GetTrackDistanceToMainAgent()
    {
      return this.GetPosition().Distance(Hero.MainHero.GetPosition());
    }

    public bool CheckTracked(BasicCharacterObject basicCharacter)
    {
      return this.Notables.Any<Hero>((Func<Hero, bool>) (t => t.CharacterObject == basicCharacter)) || this.Party.PrisonRoster.GetTroopRoster().Any<TroopRosterElement>((Func<TroopRosterElement, bool>) (t => t.Character == basicCharacter)) || this.Parties.Any<MobileParty>((Func<MobileParty, bool>) (p => p.CheckTracked(basicCharacter)));
    }

    private void CreateFigure()
    {
    }

    [SaveableProperty(142)]
    public Settlement.SiegeState CurrentSiegeState { get; private set; }

    public Clan OwnerClan
    {
      get
      {
        if (this.Village != null)
          return this.Village.Bound.OwnerClan;
        if (this.Town != null)
          return this.Town.OwnerClan;
        return this.IsHideout ? this.Hideout.MapFaction as Clan : (Clan) null;
      }
    }

    public bool IsAlerted => (double) this.NumberOfEnemiesSpottedAround >= 1.0;

    public void SetNextSiegeState()
    {
      if (this.CurrentSiegeState == Settlement.SiegeState.InTheLordsHall)
        return;
      ++this.CurrentSiegeState;
    }

    public void ResetSiegeState() => this.CurrentSiegeState = Settlement.SiegeState.OnTheWalls;

    public void AddGarrisonParty(bool addInitialGarrison = false)
    {
      GarrisonPartyComponent.CreateGarrisonParty("garrison_party_" + this.StringId + "_" + this.OwnerClan.StringId + "_1", this, addInitialGarrison);
    }

    protected override void AfterLoad()
    {
      if (this.SiegeEvent != null && this.SiegeEvent.BesiegerCamp.LeaderParty == null)
        this.SiegeEvent.FinalizeSiegeEvent();
      this._notablesCache = new MBList<Hero>();
      this.CollectNotablesToCache();
      this.Party.AfterLoad();
      foreach (Alley alley in this.Alleys)
        alley.AfterLoad();
      if (this.Town == null || (double) this._oldProsperityObsolete <= 0.0)
        return;
      this.Town.Prosperity = this._oldProsperityObsolete;
    }

    private void SpawnMilitiaParty()
    {
      MilitiaPartyComponent.CreateMilitiaParty("militias_of_" + this.StringId + "_aaa1", this);
      this.TransferReadyMilitiasToMilitiaParty();
    }

    private void TransferReadyMilitiasToMilitiaParty()
    {
      if ((double) this._readyMilitia >= 1.0)
      {
        int militiaToAdd = MathF.Floor(this._readyMilitia);
        this._readyMilitia -= (float) militiaToAdd;
        this.AddMilitiasToParty(this.MilitiaPartyComponent.MobileParty, militiaToAdd);
      }
      else
      {
        if ((int) this._readyMilitia >= -1)
          return;
        int num = MathF.Ceiling(this._readyMilitia);
        this._readyMilitia -= (float) num;
        Settlement.RemoveMilitiasFromParty(this.MilitiaPartyComponent.MobileParty, -num);
      }
    }

    private void AddMilitiasToParty(MobileParty militaParty, int militiaToAdd)
    {
      float meleeTroopRate;
      Campaign.Current.Models.SettlementMilitiaModel.CalculateMilitiaSpawnRate(this, out meleeTroopRate, out float _);
      this.AddTroopToMilitiaParty(militaParty, this.Culture.MeleeMilitiaTroop, this.Culture.MeleeEliteMilitiaTroop, meleeTroopRate, ref militiaToAdd);
      this.AddTroopToMilitiaParty(militaParty, this.Culture.RangedMilitiaTroop, this.Culture.RangedEliteMilitiaTroop, 1f, ref militiaToAdd);
    }

    private void AddTroopToMilitiaParty(
      MobileParty militaParty,
      CharacterObject militiaTroop,
      CharacterObject eliteMilitiaTroop,
      float troopRatio,
      ref int numberToAddRemaining)
    {
      if (numberToAddRemaining <= 0)
        return;
      int num = MBRandom.RoundRandomized(troopRatio * (float) numberToAddRemaining);
      float militiaSpawnChance = Campaign.Current.Models.SettlementMilitiaModel.CalculateEliteMilitiaSpawnChance(this);
      for (int index = 0; index < num; ++index)
      {
        if ((double) MBRandom.RandomFloat < (double) militiaSpawnChance)
          militaParty.MemberRoster.AddToCounts(eliteMilitiaTroop, 1);
        else
          militaParty.MemberRoster.AddToCounts(militiaTroop, 1);
      }
      numberToAddRemaining -= num;
    }

    private static void RemoveMilitiasFromParty(MobileParty militaParty, int numberToRemove)
    {
      if (militaParty.MemberRoster.TotalManCount <= numberToRemove)
      {
        militaParty.MemberRoster.Clear();
      }
      else
      {
        float num1 = (float) numberToRemove / (float) militaParty.MemberRoster.TotalManCount;
        int num2 = numberToRemove;
        for (int index = 0; index < militaParty.MemberRoster.Count; ++index)
        {
          int num3 = MBRandom.RoundRandomized((float) militaParty.MemberRoster.GetElementNumber(index) * num1);
          if (num3 > num2)
            num3 = num2;
          militaParty.MemberRoster.AddToCountsAtIndex(index, -num3, removeDepleted: false);
          num2 -= num3;
          if (num2 <= 0)
            break;
        }
        militaParty.MemberRoster.RemoveZeroCounts();
      }
    }

    public void SetSiegeStrategy(SiegeStrategy strategy) => this.SiegeStrategy = strategy;

    public void InitializeSiegeEventSide()
    {
      this.SiegeStrategy = DefaultSiegeStrategies.Custom;
      this.NumberOfTroopsKilledOnSide = 0;
      this.SiegeEngines = new SiegeEvent.SiegeEnginesContainer(BattleSideEnum.Defender, (SiegeEvent.SiegeEngineConstructionProgress) null);
      this._siegeEngineMissiles = new MBList<SiegeEvent.SiegeEngineMissile>();
      this.SetPrebuiltSiegeEngines();
    }

    public void OnTroopsKilledOnSide(int killCount) => this.NumberOfTroopsKilledOnSide += killCount;

    public void AddSiegeEngineMissile(SiegeEvent.SiegeEngineMissile missile)
    {
      this._siegeEngineMissiles.Add(missile);
    }

    public void RemoveDeprecatedMissiles()
    {
      this._siegeEngineMissiles.RemoveAll((Predicate<SiegeEvent.SiegeEngineMissile>) (missile => missile.CollisionTime.IsPast));
    }

    private void SetPrebuiltSiegeEngines()
    {
      foreach (SiegeEngineType siegeEngine in Campaign.Current.Models.SiegeEventModel.GetPrebuiltSiegeEnginesOfSettlement(this))
      {
        float siegeEngineHitPoints = Campaign.Current.Models.SiegeEventModel.GetSiegeEngineHitPoints(this.SiegeEvent, siegeEngine, BattleSideEnum.Defender);
        SiegeEvent.SiegeEngineConstructionProgress constructionProgress = new SiegeEvent.SiegeEngineConstructionProgress(siegeEngine, 1f, siegeEngineHitPoints);
        this.SiegeEngines.AddPrebuiltEngineToReserve(constructionProgress);
        this.SiegeEvent.CreateSiegeObject(constructionProgress, this.SiegeEvent.GetSiegeEventSide(BattleSideEnum.Defender));
      }
    }

    public void GetAttackTarget(
      ISiegeEventSide siegeEventSide,
      SiegeEngineType siegeEngine,
      int siegeEngineSlot,
      out SiegeBombardTargets targetType,
      out int targetIndex)
    {
      targetType = SiegeBombardTargets.None;
      targetIndex = -1;
      int targetIndex1;
      float targetPriority;
      this.SiegeEvent.FindAttackableRangedEngineWithHighestPriority(siegeEventSide, siegeEngineSlot, out targetIndex1, out targetPriority);
      if (targetIndex1 == -1 || (double) MBRandom.RandomFloat * (double) targetPriority >= (double) targetPriority)
        return;
      targetIndex = targetIndex1;
      targetType = SiegeBombardTargets.RangedEngines;
    }

    public void FinalizeSiegeEvent()
    {
      this.ResetSiegeState();
      this.SiegeEvent = (SiegeEvent) null;
      this.Party.SetLevelMaskIsDirty();
      this.Party.SetVisualAsDirty();
    }

    bool IMapEntity.IsMobileEntity => false;

    bool IMapEntity.ShowCircleAroundEntity => true;

    Vec2 IMapEntity.InteractionPosition => this.GatePosition;

    bool IMapEntity.OnMapClick(bool followModifierUsed)
    {
      if (!this.IsVisible)
        return false;
      MobileParty.MainParty.Ai.SetMoveGoToSettlement(this);
      return true;
    }

    void IMapEntity.OnOpenEncyclopedia()
    {
      Campaign.Current.EncyclopediaManager.GoToLink(this.EncyclopediaLink);
    }

    void IMapEntity.OnHover()
    {
      InformationManager.ShowTooltip(typeof (Settlement), (object) this, (object) false);
    }

    bool IMapEntity.IsEnemyOf(IFaction faction)
    {
      return FactionManager.IsAtWarAgainstFaction(this.MapFaction, faction);
    }

    bool IMapEntity.IsAllyOf(IFaction faction)
    {
      return FactionManager.IsAlliedWithFaction(this.MapFaction, faction);
    }

    public void OnPartyInteraction(MobileParty mobileParty)
    {
      if (mobileParty.ShortTermTargetSettlement == null || mobileParty.ShortTermTargetSettlement.Party.SiegeEvent != null && mobileParty != MobileParty.MainParty && mobileParty.MapFaction != mobileParty.ShortTermTargetSettlement.SiegeEvent.BesiegerCamp.LeaderParty.MapFaction || mobileParty.ShortTermTargetSettlement.Party.MapEvent != null && mobileParty != MobileParty.MainParty && mobileParty.MapFaction != mobileParty.ShortTermTargetSettlement.Party.MapEvent.AttackerSide.LeaderParty.MapFaction && (!mobileParty.ShortTermTargetSettlement.Party.MapEvent.IsSallyOut || mobileParty.MapFaction != mobileParty.ShortTermTargetSettlement.Party.MapEvent.DefenderSide.LeaderParty.MapFaction))
        return;
      if (mobileParty == MobileParty.MainParty && (mobileParty.ShortTermTargetSettlement.Party.MapEvent == null || !mobileParty.ShortTermTargetSettlement.Party.MapEvent.IsRaid || mobileParty.ShortTermTargetSettlement.Party.MapEvent.DefenderSide.NumRemainingSimulationTroops > 0) && Game.Current.GameStateManager.ActiveState is MapState activeState)
        activeState.OnMainPartyEncounter();
      if (mobileParty.ShortTermTargetSettlement.Party.MapEvent != null && mobileParty.ShortTermTargetSettlement.Party.MapEvent.IsRaid && mobileParty.DefaultBehavior == AiBehavior.RaidSettlement)
      {
        mobileParty.Ai.RethinkAtNextHourlyTick = true;
        mobileParty.Ai.SetMoveModeHold();
      }
      else
        EncounterManager.StartSettlementEncounter(mobileParty, mobileParty.ShortTermTargetSettlement);
    }

    public void GetMountAndHarnessVisualIdsForPartyIcon(
      out string mountStringId,
      out string harnessStringId)
    {
      mountStringId = "";
      harnessStringId = "";
    }

    public void SetSettlementComponent(SettlementComponent settlementComponent)
    {
      settlementComponent.Owner = this.Party;
      this.SettlementComponent = settlementComponent;
      if (this.SettlementComponent is Town)
        this.Town = this.SettlementComponent as Town;
      else if (this.SettlementComponent is Village)
      {
        this.Village = this.SettlementComponent as Village;
      }
      else
      {
        if (!(this.SettlementComponent is Hideout))
          return;
        this.Hideout = this.SettlementComponent as Hideout;
      }
    }

    public enum SiegeState
    {
      OnTheWalls,
      InTheLordsHall,
      Invalid,
    }
  }
}
